package com.mlnx.bluwifi.tp.zhengkbp;


import com.mlnx.bluwifi.tp.Packet;
import com.mlnx.bluwifi.utils.ByteBuffUtils;

import java.nio.ByteBuffer;


/**
 * Created by amanda.shan on 2017/9/13.
 */

public class ZhengKBpPacket implements Packet {

    enum State {
        HEAD, LEN, CONTANT
    }

    public static final byte[] Heads = new byte[]{(byte) 0xD0, (byte) 0xC2};

    private State state = State.HEAD;
    private int matchHeadIndex;
    private int packetLen;

    private ByteBuffer packetBuff;
    private BpLis bpLis;

    public ZhengKBpPacket(BpLis bpLis) {

        this.bpLis = bpLis;

        packetBuff = ByteBuffer.allocate(500);
        packetBuff.flip();
    }

    @Override
    public void decode(byte[] bytes, int len) {
        ByteBuffUtils.addBytes(packetBuff, bytes, len);
        while (true) {
            switch (state) {
                case HEAD:
                    if (matchHead(packetBuff)) {
                        state = State.LEN;
                    } else {
                        return;
                    }
                case LEN:
                    if (packetBuff.remaining() > 0) {
                        packetLen = packetBuff.get();
                        state = State.CONTANT;
                    } else {
                        return;
                    }
                case CONTANT:
                    if (packetBuff.remaining() >= (packetLen + 1)) {
                        byte[] contant = new byte[packetLen + 1];
                        packetBuff.get(contant);
                        proceePacket(contant);
                        state = State.HEAD;
                    } else {
                        return;
                    }
            }
        }
    }

    private void proceePacket(byte[] contant) {

        int state = BpResponse.compareByte(contant);
        if (state == -1) {

//            LogUtils.d("contant[1]:" + String.format("0x%x", contant[1]));
            switch (contant[0]) {
                // 实时数据指令
                case (byte) 0xCB:
                    // 0xCB 0x00 0x64 0x01 0xCrc
                    int pressure = 0x000000ff & contant[1];
                    pressure <<= 8;
                    pressure |= 0x000000ff & contant[2];
                    bpLis.pressure(pressure);

                    if (contant[3] == 1) {
                        bpLis.heartBeat();
                    }
                    break;
                // 返回结果指令
                case (byte) 0xCC:
                    //0xCC 0xB4 0x5E 0x4C 0x00
                    //0xCC 0x04 0x00 0x00 0x00

                    if (contant[2] == 0 && contant[3] == 0 && contant[4] == 0) {
                        bpLis.error(BpResponse.getErrorMsg(contant[1] & 0x000000ff));
                    } else {
                        int sbp = 0x000000ff & contant[1];
                        int dbp = 0x000000ff & contant[2];
                        int heart = 0x000000ff & contant[3];
                        int heartError = 0x000000ff & contant[4];

                        bpLis.bp(System.currentTimeMillis(), sbp, dbp, heart, heartError == 1);
                    }

                    break;
            }
        } else if (state == 0) {
            bpLis.commandOK();
        } else if (state == 1) {
            bpLis.commandError("从机忙无法处理");
        } else if (state == 2) {
            bpLis.commandError("指令无效");
        }
    }

    private boolean matchHead(ByteBuffer buf) {

        while (buf.remaining() > 0) {
            if (matchHeadIndex == Heads.length) {
                matchHeadIndex = 0;
                return true;
            }
            byte b = buf.get();
            if (b == Heads[matchHeadIndex]) {
                matchHeadIndex++;
            } else if (b == Heads[0]) {
                matchHeadIndex = 1;
            } else {
                matchHeadIndex = 0;
            }
        }
        return false;
    }

    public static byte[] getPingPacket() {
        return new byte[]{(byte) 0xBE, (byte) 0xB0, 0x01, (byte) 0xB0, (byte) 0xce};
    }

    public static byte[] getStartPacket() {
        return new byte[]{(byte) 0xBE, (byte) 0xB0, 0x01, (byte) 0xC0, (byte) 0x36};
    }

    public static byte[] getStropPacket() {
        return new byte[]{(byte) 0xBE, (byte) 0xB0, 0x01, (byte) 0xC1, (byte) 0x68};
    }


    public interface BpLis {

        default void commandOK() {
        }

        default void commandError(String msg) {
        }

        default void error(String msg) {
        }

        default void heartBeat() {
        }

        default void pressure(int pressure) {
        }

        default void bp(long time, int sbp, int dbp, int heart, boolean heartEror) {
        }
    }

}
